package com.googlecode.easyec.sika.csv;

import au.com.bytecode.opencsv.CSVParser;
import au.com.bytecode.opencsv.CSVReader;
import com.googlecode.easyec.sika.*;
import com.googlecode.easyec.sika.event.RowEvent;
import com.googlecode.easyec.sika.event.WorkbookBlankRowListener;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Reader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.googlecode.easyec.sika.DocType.CSV;

/**
 * Created with IntelliJ IDEA.
 * User: ZHANG78
 * Date: 12-4-25
 * Time: 下午3:31
 * To change this template use File | Settings | File Templates.
 */
public final class CsvFactory {

    private static final ThreadLocal<CsvFactory> local = new ThreadLocal<CsvFactory>();
    private static final Logger logger = LoggerFactory.getLogger(CsvFactory.class);

    private CsvFactory() {
    }

    public static CsvFactory getInstance() {
        synchronized (local) {
            CsvFactory factory = local.get();
            if (factory == null) {
                factory = new CsvFactory();
                local.set(factory);
            }

            return factory;
        }
    }

    public void read(Reader reader, WorkbookReader workbook) throws WorkingException {
        read(reader, workbook, CSVParser.DEFAULT_SEPARATOR);
    }

    public void read(Reader reader, WorkbookReader workbookReader, char separator) throws WorkingException {
        if (!workbookReader.hasMore()) {
            throw new WorkingException("No WorkbookHandler was added.", true);
        }

        WorkbookHandler handler = workbookReader.get(0);
        handler.setDocType(CSV);

        try {
            CSVReader csvReader = new CSVReader(reader, separator);

            handler.doInit();

            try {
                if (handler instanceof WorkbookRowHandler) {
                    WorkbookRowHandler rowHandler = (WorkbookRowHandler) handler;

                    WorkbookHeader header = rowHandler.getHeader();
                    int rawHeaderCount = header.getRawHeaderCount();

                    for (int i = 0; i < rawHeaderCount; i++) {
                        String[] headerData = csvReader.readNext();
                        if (headerData == null) {
                            logger.debug("No data of head was resolved.");

                            break;
                        }

                        List<WorkData> data = new ArrayList<WorkData>();
                        try {
                            for (int j = 0; j < headerData.length; j++) {
                                data.add(new CsvWorkData(headerData[j], j));
                            }

                            header.addHeader(data);
                        } finally {
                            data.clear();
                            data = null;
                        }
                    }

                    String[] line;
                    for (int i = header.getHeaderCount(); (line = csvReader.readNext()) != null; i++) {
                        List<WorkData> list = new ArrayList<WorkData>();

                        try {
                            for (int j = 0; j < line.length; j++) {
                                list.add(new CsvWorkData(line[j], j));
                            }

                            WorkbookBlankRowListener blankRowListeners = rowHandler.getBlankRowListeners();
                            if (blankRowListeners != null) {
                                if (!blankRowListeners.accept(new RowEvent(list, i))) {
                                    continue;
                                }
                            }

                            Map<Integer, List<WorkData>> map = new LinkedHashMap<Integer, List<WorkData>>();
                            map.put(i, list);

                            try {
                                if (!rowHandler.populate(map)) {
                                    break;
                                }
                            } finally {
                                map = null;
                            }
                        } catch (WorkingException e) {
                            handler.doCatch(e);
                            if (e.isStop()) {
                                break;
                            }
                        } finally {
                            list = null;
                        }
                    }
                }
            } finally {
                csvReader.close();
            }

            handler.doFinish();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);

            if (e instanceof WorkingException) {
                throw (WorkingException) e;
            }

            throw new WorkingException(e, true);
        } finally {
            handler.doFinally();

            IOUtils.closeQuietly(reader);
        }
    }
}
